/*
* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd. 
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "engine/include/service_executor.h"
#include "protocol/data_channel/include/i_request.h"
#include "engine/include/future_factory.h"
#include "engine/include/i_future.h"

namespace OHOS {
namespace AI_STD {
std::mutex ServiceExecutor::mutex_;
ServiceExecutor *ServiceExecutor::instance_ = nullptr;

ServiceExecutor *ServiceExecutor::GetInstance()
{
    CHK_RET(instance_ != nullptr, instance_);

    std::lock_guard<std::mutex> lock(mutex_);
    CHK_RET(instance_ != nullptr, instance_);

    ServiceExecutor *tempInstance = nullptr;
    AI_NEW_INSTANCE(tempInstance, ServiceExecutor);
    CHK_RET(tempInstance == nullptr, nullptr);

    if (tempInstance->Initialize() != RETCODE_SUCCESS) {
        AI_DELETE_INSTANCE(tempInstance);
        return nullptr;
    }
    instance_ = tempInstance;
    return instance_;
}

void ServiceExecutor::ReleaseInstance()
{
    std::lock_guard<std::mutex> lock(mutex_);
    AI_DELETE_INSTANCE(instance_);
}

ServiceExecutor::ServiceExecutor() : engineMgr_(nullptr)
{
}

ServiceExecutor::~ServiceExecutor()
{
    Uninitialize();
}

int ServiceExecutor::Initialize()
{
    AI_NEW_INSTANCE(engineMgr_, EngineManager);
    if (engineMgr_ == nullptr) {
        HILOGE("[ServiceExecutor]Failed to new engine manager");
        return RETCODE_OUT_OF_MEMORY;
    }
    int retCode = engineMgr_->Initialize();
    if (retCode != RETCODE_SUCCESS) {
        HILOGE("[ServiceExecutor]Failed to initialize engine manager");
        AI_DELETE_INSTANCE(engineMgr_);
    }
    return retCode;
}

void ServiceExecutor::Uninitialize()
{
    AI_DELETE_INSTANCE(engineMgr_);
    FutureFactory::ReleaseInstance();
}

int ServiceExecutor::StartEngine(long long transactionId, const AlgorithmInfo &algoInfo, const DataInfo &inputInfo,
    DataInfo &outputInfo)
{
    CHK_RET(engineMgr_ == nullptr, RETCODE_ENGINE_MANAGER_NOT_INIT);

    HILOGI("[ServiceExecutor]Begin to start engine for algorithm, algorithmName:%s.", algoInfo.algorithmName.c_str());
    return engineMgr_->StartEngine(transactionId, algoInfo, inputInfo, outputInfo);
}

int ServiceExecutor::StopEngine(long long transactionId, const DataInfo &inputInfo)
{
    CHK_RET(engineMgr_ == nullptr, RETCODE_ENGINE_MANAGER_NOT_INIT);

    HILOGI("[ServiceExecutor]Begin to stop engine for algorithm.");
    return engineMgr_->StopEngine(transactionId, inputInfo);
}

int ServiceExecutor::SetOption(long long transactionId, int optionType, const DataInfo &inputInfo)
{
    CHK_RET(engineMgr_ == nullptr, RETCODE_ENGINE_MANAGER_NOT_INIT);

    HILOGI("[ServiceExecutor]Begin to set option for algorithm.");
    return engineMgr_->SetOption(transactionId, optionType, inputInfo);
}

int ServiceExecutor::GetOption(long long transactionId, int optionType, const DataInfo &inputInfo,
    DataInfo &outputInfo)
{
    CHK_RET(engineMgr_ == nullptr, RETCODE_ENGINE_MANAGER_NOT_INIT);

    HILOGI("[ServiceExecutor]Begin to get option for algorithm.");
    return engineMgr_->GetOption(transactionId, optionType, inputInfo, outputInfo);
}

int ServiceExecutor::SyncExecute(IRequest *request, IResponse *&response)
{
    CHK_RET(engineMgr_ == nullptr, RETCODE_ENGINE_MANAGER_NOT_INIT);
    CHK_RET(request == nullptr, RETCODE_NULL_PARAM);
    HILOGI("[ServiceExecutor]Begin to call SyncExecute, algoType:%s.", request->GetAlgoPluginType().c_str());

    std::shared_ptr<Engine> engine = engineMgr_->FindEngine(request->GetTransactionId());
    CHK_RET(engine == nullptr, RETCODE_ENGINE_NOT_EXIST);

    return engine->SyncExecute(request, response);
}

int ServiceExecutor::AsyncExecute(IRequest *request)
{
    if (engineMgr_ == nullptr) {
        HILOGI("[ServiceExecutor]The engineMgr_ is null.");
        return RETCODE_ENGINE_MANAGER_NOT_INIT;
    }

    if (request == nullptr) {
        HILOGI("[ServiceExecutor]The request is null.");
        return RETCODE_NULL_PARAM;
    }

    std::shared_ptr<Engine> engine = engineMgr_->FindEngine(request->GetTransactionId());
    CHK_RET(engine == nullptr, RETCODE_ENGINE_NOT_EXIST);

    int retCode = engine->AsyncExecute(request);
    if (retCode != RETCODE_SUCCESS) {
        HILOGE("[ServiceExecutor]Engine AsyncExecute failed, retCode is %d.", retCode);
    }
    return retCode;
}

int ServiceExecutor::RegisterListener(IFutureListener *listener, long long transactionId)
{
    FutureFactory *futureFactory = FutureFactory::GetInstance();
    CHK_RET(futureFactory == nullptr, RETCODE_NULL_PARAM);
    futureFactory->RegisterListener(listener, transactionId);
    return RETCODE_SUCCESS;
}

int ServiceExecutor::UnRegisterListener(long long transactionId)
{
    FutureFactory *futureFactory = FutureFactory::GetInstance();
    CHK_RET(futureFactory == nullptr, RETCODE_NULL_PARAM);
    futureFactory->UnregisterListener(transactionId);
    return RETCODE_SUCCESS;
}

ISyncTaskManager *GetSyncTaskManager()
{
    return ServiceExecutor::GetInstance();
}

IAsyncTaskManager *GetAsyncTaskManager()
{
    return ServiceExecutor::GetInstance();
}

IEngineManager *GetEngineManager()
{
    return ServiceExecutor::GetInstance();
}

void ReleaseEngineManager()
{
    return ServiceExecutor::ReleaseInstance();
}
} // namespace AI_STD
} // namespace OHOS
